#include "float.h"

double Float::precision = 1000000; //this value will essentially set how precise the raiseto function is with doubles.
double Float::precision_mult = 100; 
double Float::equals_precision = 0.00002;
Float::Float() {
	value = 0.0; 	
} 

Float::Float(double value)
{
	try {
	
		this->value = (double)value; 
	} catch(...) {
		std::cerr << "couldn't initialize " << this << std::endl;
		throw "Couldn't initilialize object!"; 
	
	} 
} 


Float::~Float()
{
//	cout << "Float " << this << " has been deleted" << std::endl;
} 

bool Float::setprecision(double new_precision, double new_precision_mult, double new_equals_precision)
{
// the 100000 value is because any less than that results in BAD inaccuracy with the raseto function. 
// the 100000000 (or whatever) value is somewhat arbitrary, but any greater and the == function will get
// too stingy and the raiseto function takes a lot of time.
	if(new_precision < 100000 || new_precision > 100000000) {
		std::cerr << "precision value invalid!" << std::endl;
		return false; 
	} else {
		Float::precision = new_precision;
		return true;
	} 

	if((int)new_precision_mult > 1000 || (int)new_precision_mult < 1) {
		std::cerr << "Precision value for precision_mult invalid!" << std::endl;
		return false; 
	} else {
		Float::precision_mult = new_precision_mult;
		return true; 
	} 

	if((int)new_equals_precision > 1.0 || (int)new_equals_precision < 0) {
		std::cerr << "new equals precision invalid!" << std::endl;
		return false; 
	} else {
		Float::equals_precision = new_equals_precision;
		return true; 
	} 
} 
Float Float::raiseto(int power) //this method will raise the Float to the nth integer power
{
	Float ret(1.0);

	if(power == 0) {
		return 1; 
	} else if(power < 0) {
		
		for(int i = 0; i< -1 * power; i++) //simple for loop. 2^2 is 2 * 2. we want to multiply 2 twice - so I say 1 * 2 * 2, just to make the for loop more understandable.
			ret *= value;	

		ret = 1.0/value;
	
		return ret;
	} else {
		for(int i = 0; i< power; i++) //simple for loop. 2^2 is 2 * 2. we want to multiply 2 twice - so I say 1 * 2 * 2, just to make the for loop more understandable.
			ret *= value;	
		 

		return ret;
		
	} 	
	  	 

} 

Float Float::square()   //this method squares the float - using less clock cycles to do so.
{
   return *this * *this;
}
//In this function, we can take roots of things, 'n such. 
//Its operation is based on this: x^n = x^(n*10/10) = x^(1/10)*n*10 - so we can just find the tenth root, and raise it to the n*10 - or any other number. The tenth root
//for example, if we have 4^.5, then this can be rewritten as 4^((1/10)*5) so we find the tenth root of four and raise that to the fifth power.
Float Float::raiseto(double power, double frac_precision_multiplier=1.0 )  
{						  
	double frac_precision;
  if((int)frac_precision_multiplier <= 1000) { 
  	frac_precision = 100.0 * frac_precision_multiplier;
  } else if((int)frac_precision_multiplier > 1000) {
	frac_precision = 100000.0; 
  } else {
	 frac_precision = 100.0; 
  } 
  double incsize = 1.0; 
  double preciseinv = 1.0/(precision * precision_mult); 
  int Topside = power * (int)frac_precision; 			
  
  Float * base = new Float(1.0); 
  
  while(1) {

	if(base->raiseto((int)frac_precision) >= this->value) {

		if(incsize <= preciseinv) {
			break;
		} else {	
			base->value -= incsize; 
			 incsize /= 10.0;
		} 
	} else {

		base->value += incsize; 
	}
  } 

  Float returnval  = base->raiseto((int)Topside); 
 
  delete base;  	 	 
  return returnval;  
   
} 
 

Float::operator double() 
{
	return value; 
} 

Float::operator float() 
{
	return value; 
} 


Float::operator int() 
{
	return static_cast<int>(value); 
} 


Float Float::operator+=(const Float in)
{
	value += in.value; 
	return *this;
} 
Float Float::operator+(const Float in)
{
	Float tmp = *this; 
	tmp += in;  
	return tmp;
} 


Float Float::operator+=(const double in)
{
	value += in; 
	return *this;
} 
Float Float::operator+(const double in)
{
	Float tmp = *this; 
	tmp += in; 
	return tmp;  
	
} 

Float Float::operator-=(const double in)
{
	value -= in; 
	return *this; 
} 
Float Float::operator-(const double in)
{
	Float tmp = *this; 
	tmp -= in;
	return tmp;
}

Float Float::operator-=(const Float in)
{
	value -= in.value; 
	return *this;
} 

Float Float::operator-(const Float in)
{
	Float tmp = *this;
	tmp -= in;
	return tmp;
}

Float Float::operator*=(const double in)
{
	value *= in; 
	return *this;
} 

Float Float::operator* (const double in)
{
	Float tmp = *this;
	tmp *= in; 
	return tmp;
} 


Float Float::operator*= (const Float in)
{
	value *= in.value; 
	return *this;
} 

Float Float::operator* (const Float in)
{
	Float tmp = *this;
	tmp *= in; 
	return tmp;
} 

Float Float::operator/=(const double in)
{
	this->value = value / in;
	return *this;
} 

Float Float::operator/ (const double in)
{
	Float tmp = *this;
	tmp /= in;
	return tmp;
} 

Float Float::operator/=(const Float in)
{
	value /= in.value;
	return *this;
} 

Float Float::operator/ (const Float in)
{
	Float tmp = *this;
	tmp /= in;
	return tmp;
} 	
Float Float::operator=(const double in)
{	
	value = in; 
	return *this; 
} 

Float Float::operator=(const Float in)
{
	if(this == &in)
		return *this; 
	else
		value = in.value; 
	return *this; 
} 	 

void Float::operator++(int)
{
	value += 1; 
} 
void Float::operator--(int)
{
	value -= 1; 
} 

bool Float::operator <= (const Float in) const
{
	if(value <= in.value) {
		return true;
	} else {
		return false;
	}
} 	
bool Float::operator <= (const double in) const
{
	if(value <= in) {
		return true;
	} else {
		return false;
	}
}

bool Float::operator >= (const Float in) const
{
	if(value >= in.value) {
		return true;
	} else {
		return false;
	}
} 

bool Float::operator >= (const double in) const
{
	if(value >= in) {
		return true;
	} else {
		return false;
	}
}

bool Float::operator > (const double in) const
{
	if(value > in) {
		return true;
	} else {
		return false; 
	}
} 

bool Float::operator > (const Float in) const
{
	if(value > in.value) {
		return true;
	} else {
		return false; 
	} 
} 

bool Float::operator < (const double in) const
{
	if(value < in) {
		return true;
	} else {
		return false; 
	} 
}

bool Float::operator < (const Float in) const
{
	if(value < in.value) {
		return true;
	} else {
		return false; 
 	}
}   


 
